/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.dnd;

import java.util.List;

import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.dnd.AbstractTransferDropTargetListener;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Connector;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.ExtensionPoint;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Reception;
import org.eclipse.uml2.uml.Relationship;
import org.eclipse.uml2.uml.TemplateParameter;
import org.eclipse.uml2.uml.TemplateSignature;

import com.cea.papyrus.core.editpart.FeatureListEditPart;
import com.cea.papyrus.core.editpart.GraphNodeWithSemanticEditPart;
import com.cea.papyrus.core.helper.IGraphElementHelper;
import com.cea.papyrus.core.helper.IModelerHelper;
import com.cea.papyrus.core.helper.ModelerHelper;
import com.cea.papyrus.diagraminterchange2.di2.Diagram;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.extensionpoints.dnd.parsing.GlobalDNDFilter;

//import com.cea.papyrus.componentdiagram.editpart.ComponentDiagramEditPart;
//import com.cea.papyrus.core.composite.editpart.CompositeDiagramEditPart;

/**
 * 
 */
public class GraphicalPageWithFlyoutPaletteDropTargetListener extends AbstractTransferDropTargetListener {

	/**
	 * 
	 * 
	 * @param viewer 
	 */
	public GraphicalPageWithFlyoutPaletteDropTargetListener(EditPartViewer viewer) {
		super(viewer, ObjectTransfer.getInstance());
		// TODO Auto-generated constructor stub
	}

	/**
	 * 
	 * 
	 * @param event 
	 * 
	 * @return 
	 */
	public boolean isEnabled(DropTargetEvent event) {
		boolean result = super.isEnabled(event);
		if (result) {
			updateTargetRequest();
			updateTargetEditPart();

//			test in order to know if the drag and drop may be made
			// forbidden to drop a diagram
			if(((List)((ObjectTransfer)getTransfer()).getObject()).get(0)instanceof Diagram )
			{return false;}
			Element elt=(Element)((List)((ObjectTransfer)getTransfer()).getObject()).get(0);
			//case of an element import
			//if (elt instanceof ElementImport){
			//	elt=((ElementImport)elt).getImportedElement();
			//}
			if (!(elt instanceof Relationship)&&!( elt instanceof Connector)){
				java.lang.Class elementClass=elt.getClass().getInterfaces()[0];
				IModelerHelper imodelerFactory= ModelerHelper.getFactory();
				IGraphElementHelper elementFactory = (IGraphElementHelper)imodelerFactory.getElementFactory(elementClass);
				if(elementFactory == null) {
					return false;
				}


//				if it can not be created, return false

				Element umlParent=null;
				//case of property It is complex because of the composie diagram
				//in this case the Graphical parent may be a property
				if(elt instanceof Property){
					//case of class diagram
					if ((getTargetEditPart() instanceof  FeatureListEditPart)){
						umlParent=((GraphNodeWithSemanticEditPart)((getTargetEditPart().getParent()))).getUmlElement();	
						if (!elt.getOwner().equals(umlParent)){
							return false;
						}
					}
					else{
						//case of composite diagram
						if(getTargetEditPart() instanceof GraphNodeWithSemanticEditPart){
							umlParent=((GraphNodeWithSemanticEditPart)((getTargetEditPart()))).getUmlElement();	
							//the graphical owner is a property
							if((umlParent instanceof Property )&& (((Property)umlParent).getType()!=null)){
								if((((Property)umlParent).getType() instanceof Classifier)&&
										((Classifier)((Property)umlParent).getType())
										.getAllAttributes().contains(elt)){
									return true;
								}
							}
							//else case of Classifier
							if (!(umlParent instanceof Classifier) || !((Classifier)umlParent).getAllAttributes().contains(elt)){
								return false;
							}

						}
					}
				}
				umlParent=null;
				
				if(elt instanceof Reception) {
					//case of class diagram
					if ((getTargetEditPart() instanceof  FeatureListEditPart)){
						umlParent=((GraphNodeWithSemanticEditPart)((getTargetEditPart().getParent()))).getUmlElement();	
						if (!elt.getOwner().equals(umlParent)){
							return false;
						}
					}
				}
				umlParent=null;
				
//				FIXME: To redesign test
				//we have to test if the parent is the same
				if ((elt instanceof Operation ||
						elt instanceof TemplateParameter|| elt instanceof ExtensionPoint)){
					if (!(getTargetEditPart() instanceof  FeatureListEditPart)){
						return false;
					}
					else{
						umlParent=((GraphNodeWithSemanticEditPart)((getTargetEditPart().getParent()))).getUmlElement();	
						if (!elt.getOwner().equals(umlParent)){
							return false;
						}
					}
				}
				if (elt instanceof TemplateSignature) {
					if (getTargetEditPart() instanceof GraphNodeWithSemanticEditPart) {
						umlParent = ((GraphNodeWithSemanticEditPart)getTargetEditPart()).getUmlElement();
						if (!elt.getOwner().equals(umlParent))
							return false;
					}
				}

				// Test other filter for dnd registered as extension 
				// in diagram specific plugins
				// This replace the following commented code
				if (! GlobalDNDFilter.select(elt, getTargetEditPart())) {
					return false;
				}

				// --> Filter declared as extension in StateMachineDiagram plugin

//				//additional tests for regions
//				if(elt instanceof Region){
//				if(getTargetEditPart() instanceof RegionEditPart){
//				//check whether the container to be (statemachine or state) has not already got a node representing the region
//				if(((RegionEditPart)getTargetEditPart()).getModel() == null)
//				return false;
//				GraphNode semParent = (GraphNode)((GraphNode)((RegionEditPart)getTargetEditPart()).getModel()).getSemanticParent();
//				if(semParent == null)
//				return false;
//				Iterator it = semParent.getSemanticChild().iterator();
//				boolean found = false;
//				while(!found && it.hasNext()){
//				GraphNode current = (GraphNode)it.next();
//				if(current.getSemanticModel() != null){
//				if(((Uml1SemanticModelBridge)current.getSemanticModel()).getElement().equals(elt))
//				found = true;
//				}
//				}
//				if(found)
//				return false;
//				else
//				return true;
//				}				
//				}

				// --X

				// --> Filter declared as extension in ComponentDiagramEditPart plugin
				// --> Filter declared as extension in CompositeDiagram plugin

//				// test to disable DnD from outline to ComponentDiagram or Composite for Interface
//				if (elt instanceof org.eclipse.uml2.uml.Interface){
//				if (getTargetEditPart() instanceof ComponentDiagramEditPart ||
//				getTargetEditPart() instanceof CompositeDiagramEditPart ) {
//				return false;
//				}
//				}	// end disable Interface

				// --X

				return  elementFactory.canCreateGraphElement((GraphElement)getTargetEditPart().getModel());
			}
			else {
				//move nodes
				EditPart part = getTargetEditPart();
				if(part != null) {
					Command command = part.getCommand(getTargetRequest());
					if(command != null) {
						return command.canExecute();
					}
				}


			}
		}
		return result;
	}


	/**
	 * 
	 * 
	 * @return 
	 */
	protected Request createTargetRequest() {
		CreateRequest req = new CreateRequest();
		List transfer = (List)((ObjectTransfer)getTransfer()).getObject();
		req.getExtendedData().put(ObjectTransfer.UML_TRANSFER_OBJECT, transfer);
		return req;
	}

	/**
	 * 
	 */
	@Override
	protected void updateTargetRequest() {
		CreateRequest req = (CreateRequest)getTargetRequest();
		req.setLocation(getDropLocation());
	}


}

